#include "DataStream.h"
#include "CompilerCapability.h"

_BEGIN_NETWORK_NAMESPACE_

const size_t OutputDataStream::DefaultCapacity = 1024;


OutputDataStream::OutputDataStream( size_t capacity )
: m_capacity( capacity )
{
	m_buffer = new char[m_capacity];
	m_curData = m_buffer;
	dcmemset( m_buffer, 0, sizeof( char ) * m_capacity );
}


OutputDataStream::~OutputDataStream()
{
}


unsigned int OutputDataStream::GetCapacity() const
{
	return m_capacity;
}


unsigned int OutputDataStream::GetSize() const
{
	return m_curData - m_buffer;
}


const char * OutputDataStream::GetBuffer() const
{
	return m_buffer;
}


OutputDataStream & OutputDataStream::operator<<( bool data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( char data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( unsigned char data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( int data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( unsigned int data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( long data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( unsigned long data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( float data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( double data )
{
	return this->WriteData( data );
}


OutputDataStream & OutputDataStream::operator<<( const tchar * str )
{
	// Append the '\0' here to calculate the buffer size.
	size_t size = tstrlen( str ) + 1;

	const char * strTail = reinterpret_cast<const char *>( str + size );
	const char * strHead = reinterpret_cast<const char *>( str );

	this->Write( strHead, strTail - strHead );
	return *this;
}


OutputDataStream & OutputDataStream::operator<<( const tstring & str )
{
	return *this << str.c_str();
}


OutputDataStream & OutputDataStream::operator<<( const IDataWritable & data )
{
	data.WriteToStream( *this );
	return *this;
}


void OutputDataStream::Write( const char * data, size_t size )
{
	this->ValidataBufferSize( size );

	dcmemcpy( m_curData, data, size );
	m_curData += size;
}


void OutputDataStream::ValidataBufferSize( size_t size )
{
	if( m_curData + size > m_buffer + m_capacity )
	{
		size_t extraSize = m_curData + size - ( m_buffer + m_capacity );
		this->EnlargeBuffer( extraSize );
	}
}


void OutputDataStream::EnlargeBuffer( size_t size )
{
	// Here, we got a strange algorithm to calculate the new size.
	// The '[   ]' means the entire capacity.
	// The '-' means the original data.
	// The '+' means the data to append.
	// The '*' means the tail of data which should be append.
	// [---][+* ]
	// [---][+++][+* ][   ]
	// [---][+++][+++][+* ][   ][   ]
	size_t enlargeRatio = ( size / m_capacity + 1 ) * 2;
	size_t newCapacity = m_capacity * enlargeRatio;
	size_t dataOffset = this->GetSize();

	char * newBuffer = new char[newCapacity];
	dcmemcpy( newBuffer, m_buffer, m_capacity );
	delete[] m_buffer;

	m_buffer = newBuffer;
	m_curData = m_buffer + dataOffset;
	m_capacity = newCapacity;
}


_END_NETWORK_NAMESPACE_